package initialize

import (
	"context"
	"errors"
	"fmt"
	"go-proxy/utils"
	"time"

	"go.uber.org/zap"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

var ErrRecordNotFound = errors.New("record not found")

// GetTable 获取模式下的表名
const GetTable = "select name from sqlite_master where type='table'"

type zapLogger struct {
	zap                       *zap.Logger
	SlowThreshold             time.Duration
	Parameterized             bool
	IgnoreRecordNotFoundError bool
}

func (l *zapLogger) LogMode(level logger.LogLevel) logger.Interface {
	return l
}

func (l *zapLogger) Info(ctx context.Context, msg string, data ...interface{}) {
	if l.zap.Level() >= zap.InfoLevel {
		l.zap.Info(msg, zap.Any("data", data))
	}
}

func (l *zapLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
	if l.zap.Level() >= zap.WarnLevel {
		l.zap.Warn(msg, zap.Any("data", data))
	}
}

func (l *zapLogger) Error(ctx context.Context, msg string, data ...interface{}) {
	if l.zap.Level() >= zap.ErrorLevel {
		l.zap.Error(msg, zap.Any("data", data))
	}
}

func (l *zapLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
	if l.zap.Level() <= zap.DebugLevel {
		return
	}

	elapsed := time.Since(begin)
	sql, rows := fc()

	fields := []zap.Field{
		zap.String("duration", fmt.Sprintf("%.3fms", float64(elapsed.Nanoseconds())/1e6)),
		zap.String("sql", sql),
	}

	if rows != -1 {
		fields = append(fields, zap.Int64("rows", rows))
	}

	switch {
	case err != nil && (!l.IgnoreRecordNotFoundError || !errors.Is(err, ErrRecordNotFound)):
		fields = append(fields, zap.String("error", err.Error()))
		l.zap.Error("sql executed", fields...)

	case l.SlowThreshold != 0 && elapsed > l.SlowThreshold:
		l.zap.Warn("sql executed", fields...)

	case l.zap.Level() >= zap.InfoLevel:
		l.zap.Error("sql executed", fields...)
	}
}

func initTable() {
	var (
		tables   []string
		tableMap = map[string]any{}
		err      error
	)

	if DB, err = gorm.Open(sqlite.Open(Config.DB.DbPath), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
		Logger: &zapLogger{
			zap:                       Logger,
			SlowThreshold:             200 * time.Millisecond,
			IgnoreRecordNotFoundError: false,
		},
	}); err != nil {
		panic("获取系统数据异常: " + err.Error())
	}

	if Config.DB.InitTable {
		if err = DB.Raw(GetTable).Scan(&tables).Error; err == nil {
			for key, value := range tableMap {
				if exist, _ := utils.In[string](key, tables); !exist {
					if err = DB.AutoMigrate(&value); err != nil {
						Logger.Error("生成数据表失败", zap.String("table", key), zap.String("error", err.Error()))
						continue
					}
					Logger.Info("生成表" + key + "完成")
				}
			}
		}
	}
}
